%{

#include "commonXML.h"

int xslwrap(void);
void xslerror(XML** xml, char *msg);
void xslerror(XML** xml, const char *msg);
int xsllex(void);
bool isValidXsl = true;
vector<ElementName * > stackOpenCloseTagXsl;


%}

%union {
   char * s;
   ElementName * en;  /* le nom d'un element avec son namespace */
   vector<AttributeXML*> * liste_attr;
   AttributeXML *  attribut_t;
   vector<NodeXML *> * liste_nodes;
   ElementXML * elem;
   XML * xml_t;
}

%token EQ SLASH CLOSE CLOSESPECIAL DOCTYPE XSLSTYLESHEET
%token <s> ENCODING STRING DATA COMMENT IDENT NSIDENT
%token <en> NSSTART START STARTSPECIAL END NSEND

%type <liste_attr> attribut_opt
%type <liste_nodes> empty_or_content
%type <liste_nodes> close_content_and_end
%type <liste_nodes> content_opt
%type <elem> xml_element
%type <en> start
%type <s> declaration
%type <s> declarations_opt
%type <s> declarations_opt_xsl
%type <s> declaration_xsl
%type <attribut_t> attribut
%type <xml_t> document

%parse-param{XML ** xml}
%%

document
 : declarations_opt_xsl declarations_opt xml_element misc_seq_opt { *xml = new XML($1, $2, $3, isValidXsl);}
 ;

misc_seq_opt
 : misc_seq_opt comment
 | /*empty*/
 ;

comment
 : COMMENT
 ;

declarations_opt_xsl
 : declaration_xsl { $$ = $1 ;}
 | /*empty*/{ $$ = NULL ;}
 ;

declaration_xsl
 : XSLSTYLESHEET attribut attribut CLOSESPECIAL {
							if($2->getName().compare("href") ==0)
								$$ = (char*)$2->getValue().c_str();
							else if($3->getName().compare("href") ==0)
								$$ = (char*)$3->getValue().c_str();
							else
							{
								xslerror(NULL, "====================ERROR====================\n");
								xslerror(NULL, "It seems that the href attribute is missing");
								xslerror(NULL, "\n====================END ERROR====================\n");
							}
                                                }
 ;

declarations_opt
 : declaration {$$ = $1;}
 | /*empty*/{$$ = NULL;}
 ;

declaration
 : DOCTYPE IDENT IDENT STRING CLOSE {$$ = $4;}//{ *xml = new XML; *xml->setDTD($4); }
 ;

attribut
 : IDENT EQ STRING { $$ = new AttributeXML($1,$3); }
 | NSIDENT EQ STRING { $$ = new AttributeXML($1,$3); }
;

attribut_opt
 : attribut_opt attribut { $$ = $1; $$->push_back($2);  }
 | /*empty*/ { $$ = new vector<AttributeXML * >; } 
 ;

xml_element
 : start attribut_opt empty_or_content { $$ = new ElementXML(($3), ($2), $1->first,$1->second, false); }
 | start attribut_opt SLASH CLOSE { 
					vector<NodeXML *>* temp = new vector<NodeXML *>;
					$$ = new ElementXML(temp, ($2), $1->first,$1->second, true); 
					stackOpenCloseTagXsl.pop_back();
				  } 
 ;
start
 : START { $$ = $1; stackOpenCloseTagXsl.push_back($$);} 
 | NSSTART { $$ = $1; stackOpenCloseTagXsl.push_back($$);} 
 ;
empty_or_content
 : close_content_and_end CLOSE {$$ = $1}
 ;
close_content_and_end
 : CLOSE content_opt END {
				$3->second.erase(0, 1);
				//Error management for tag problems
				if(stackOpenCloseTagXsl.size() <= 0)
				{
					xslerror(NULL, "====================ERROR====================\n");
					xslerror(NULL, "stack is empty, but there is a closing tag: ");
					xslerror(NULL, $3->second.c_str());
					xslerror(NULL, "\n");
					xslerror(NULL, "====================END ERROR====================\n");
				}
				else
				{
					if(!stackOpenCloseTagXsl.back()->first.empty())
					{	
						xslerror(NULL,"====================ERROR====================\n");
						xslerror(NULL, "It seems that a namespace is missing for the tag: ");
						xslerror(NULL, $3->second.c_str());
						xslerror(NULL, "\nTIPS: You should add the namespace \"");
						xslerror(NULL, stackOpenCloseTagXsl.back()->first.c_str()); 
						xslerror(NULL, "\"\n====================END ERROR====================\n");
					}
					else if(stackOpenCloseTagXsl.back()->second.compare($3->second)!=0)
					{
						xslerror(NULL,"====================ERROR====================\n");
						xslerror(NULL, "It seems that one of this tag is not correct: \"");
						xslerror(NULL, $3->second.c_str());
						xslerror(NULL, "\" or \"");
						xslerror(NULL, stackOpenCloseTagXsl.back()->second.c_str());
						xslerror(NULL, "\".\nTIPS: You should correct it by \"");
						xslerror(NULL, stackOpenCloseTagXsl.back()->second.c_str());
						xslerror(NULL, "\" or change the tag \"");
						xslerror(NULL, stackOpenCloseTagXsl.back()->second.c_str());
						xslerror(NULL, "\" by \"");
						xslerror(NULL, $3->second.c_str());
						xslerror(NULL, "\"\n");
						xslerror(NULL, "====================END ERROR====================\n");
					}
					stackOpenCloseTagXsl.pop_back();
				}
				$$ = $2;
			}
 | CLOSE content_opt NSEND {
				$3->first.erase(0, 1);
				//Error management for tag problems
				if(stackOpenCloseTagXsl.size() <= 0)
				{
					xslerror(NULL, "====================ERROR====================\n");
					xslerror(NULL, "stack is empty, but there is a closing tag: ");
					xslerror(NULL, $3->second.c_str());
					xslerror(NULL, "\n");
					xslerror(NULL, "====================END ERROR====================\n");
				}
				else 
				{
					if(stackOpenCloseTagXsl.back()->first.empty())
					{	
						xslerror(NULL,"====================ERROR====================\n");
						xslerror(NULL, "It seems that a namespace is missing for the tag: ");
						xslerror(NULL, stackOpenCloseTagXsl.back()->second.c_str());
						xslerror(NULL, "\"\n");
						xslerror(NULL, "====================END ERROR====================\n");
					}
					else if(stackOpenCloseTagXsl.back()->first.compare($3->first) !=0 || stackOpenCloseTagXsl.back()->second.compare($3->second)!=0)
					{
						xslerror(NULL,"====================ERROR====================\n");
						xslerror(NULL, "It seems that a starting tag is missing for the tag: ");
						xslerror(NULL, $3->first.c_str());
						xslerror(NULL, ":");
						xslerror(NULL, $3->second.c_str());
						xslerror(NULL, "\n");
						xslerror(NULL, "====================END ERROR====================\n");
					}
					stackOpenCloseTagXsl.pop_back();
				}
				$$ = $2;
			}
 ;
content_opt 
 : content_opt DATA {$$ = $1; $$->push_back(new TextXML($2));}
 | content_opt comment {$$=$1;}//On ignore les commentaires
 | content_opt xml_element { $$ = $1; $$->push_back($2);}
 | /*empty*/ { $$ = new vector<NodeXML *>; }
 ;
%%

/*int main(int argc, char **argv)
/* The main must be commented for integration */
/*int main(int argc, char **argv)
{
  int err;

  //xmldebug = 1; // pour enlever l'affichage de l'éxécution du parser, commenter cette ligne

  XML * xml;
  err = xmlparse(&xml);
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
        else  printf("Parse ended with success\n", err);

   cout << xml->toString();
  cout<< xml->getDTD();
  return 0;
} 
/*int yywrap(void){
}*/


int xslwrap(void)
{
  return 1;
}


void xslerror(XML ** xml,char *msg)
{
  isValidXsl = false;
  fprintf(stderr, "%s", msg);
}


void xslerror(XML ** xml, const char *msg)

{
  isValidXsl = false;
  fprintf(stderr, "%s", msg);
}
